package org.ssssssss.example.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * json处理类
 *
 * @author <a href="mailto:zhangsj5@asiainfo.com">zhangsj</a> 2018-02-25 19:48
 **/
public class JacksonUtil {
    /**
     * 将对象转化成json
     *
     * @param object 对象
     * @return json字符串
     * @throws JsonProcessingException json异常
     */
    public static <T> String toJson(T object) throws JsonProcessingException {
        return OBJECT_MAPPER.get().writeValueAsString(object);
    }

    /**
     * 将json转化成bean
     *
     * @param json      json字符串
     * @param valueType class类型
     * @return 对象
     * @throws IOException IO异常
     */
    public static <T> T toEntity(String json, Class<T> valueType) throws IOException {
        return OBJECT_MAPPER.get().readValue(json, valueType);
    }

    /**
     * 将json转化成bean
     *
     * @param json        json字符串
     * @param elementType class类型
     * @return 对象
     * @throws IOException IO异常
     */
    public static <T> T toCollectionEntity(String json, Class<?> collectionType, Class<?> elementType) throws IOException {
        ObjectMapper objectMapper = OBJECT_MAPPER.get();
        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionType, elementType);
        return OBJECT_MAPPER.get().readValue(json, javaType);
    }


    /**
     * 将json转化成List
     *
     * @param json            json字符串
     * @param collectionClass 数组类型
     * @param elementClass    数组元素类型
     * @return 数组
     * @throws IOException IO异常
     */
    @SuppressWarnings("rawtypes")
    public static <T> List<T> toList(String json, Class<? extends List> collectionClass, Class<T> elementClass)
            throws IOException {
        JavaType javaType = OBJECT_MAPPER.get().getTypeFactory().constructCollectionType(collectionClass, elementClass);
        return OBJECT_MAPPER.get().readValue(json, javaType);
    }

    /**
     * 将json转化成Map
     *
     * @param json       json字符串
     * @param mapClass   map类型
     * @param keyClass   map.key类型
     * @param valueClass map.value类型
     * @return map对象
     * @throws IOException IO异常
     */
    @SuppressWarnings("rawtypes")
    public static <K, V> Map<K, V> toMap(String json, Class<? extends Map> mapClass, Class<K> keyClass,
                                         Class<V> valueClass) throws IOException {
        JavaType javaType = OBJECT_MAPPER.get().getTypeFactory().constructMapType(mapClass, keyClass, valueClass);
        return OBJECT_MAPPER.get().readValue(json, javaType);
    }

    /**
     * 将json转化成Map
     *
     * @param json json字符串
     * @return map对象
     * @throws IOException IO异常
     */
    public static Map<String, Object> toMap(String json) throws IOException {
        return toMap(json, HashMap.class, String.class, Object.class);
    }


    // ################################################################################################################

    /**
     * 禁止调用无参构造
     *
     * @throws IllegalAccessException
     */
    private JacksonUtil() throws AssertionError {
        throw new AssertionError("Can't create an instance!");
    }


    /**
     * 使用ThreadLocal创建对象，防止出现线程安全问题
     */
    private static final ThreadLocal<ObjectMapper> OBJECT_MAPPER = new ThreadLocal<ObjectMapper>() {
        @Override
        protected ObjectMapper initialValue() {
            ObjectMapper objectMapper = new ObjectMapper();
            // 忽略不存在的字段
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            //允许出现单引号
            objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
            //允许出现特殊字符和转义符
            objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
            objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
            objectMapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
            return objectMapper;
        }
    };

}
